home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / utility1 / gsview08.zip / DISPLAY.C < prev    next >
C/C++ Source or Header  |  1993-07-06  |  18KB  |  707 lines

  1. /*
  2.  * display.c -- Ghostscript display operations for GSVIEW.EXE, 
  3.  *              a graphical interface for MS-Windows Ghostscript
  4.  * Copyright (C) 1993  Russell Lang
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   Author: Russell Lang
  21.  * Internet: rjl@monu1.cc.monash.edu.au
  22.  */
  23.  
  24. #define STRICT
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <commdlg.h>
  28. #include <shellapi.h>
  29. #include <mmsystem.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <dir.h>
  35. #include <io.h>
  36. #define NeedFunctionPrototypes 1
  37. #include "ps.h"
  38. #include "gsview.h"
  39.  
  40. struct ftime dftime;    /* time/date of selected file */
  41. long dflength;        /* length of selected file */
  42.  
  43. /* get current media index to papersizes[], or -1 if no match */
  44. int
  45. get_papersizes_index()
  46. {
  47. int i;
  48. char medianame[20];
  49.     GetMenuString(hmenu, media, medianame, sizeof(medianame), MF_BYCOMMAND);
  50.     for (i=0; papersizes[i].name != (char *)NULL; i++) {
  51.         if (!stricmp(papersizes[i].name, medianame))
  52.         return i;
  53.     }
  54.     return -1;
  55. }
  56.  
  57. /* calculate bitmap size for gswin */
  58. void
  59. gswin_size()
  60. {
  61. int i = get_papersizes_index();
  62.     if ( (xdpi == 0.0) || (ydpi == 0.0) )
  63.         xdpi = ydpi = DEFAULT_RESOLUTION;
  64.     epsf_clipped = FALSE;
  65.     switch (orientation) {
  66.         case IDM_LANDSCAPE:
  67.         case IDM_SEASCAPE:
  68.         if (i < 0) {
  69.             bitmap_width = user_height;
  70.             bitmap_height = user_width;
  71.         }
  72.         else {
  73.             bitmap_width = papersizes[i].height;
  74.             bitmap_height = papersizes[i].width;
  75.         }
  76.         break;
  77.         default:
  78.         if ((doc != (struct document *)NULL) && doc->epsf
  79.             && epsf_clip) {
  80.             epsf_clipped = TRUE;
  81.             bitmap_width = doc->boundingbox[URX] - doc->boundingbox[LLX];
  82.             bitmap_height = doc->boundingbox[URY] - doc->boundingbox[LLY];
  83.         }
  84.         else if (i < 0) {
  85.             bitmap_width = user_width;
  86.             bitmap_height = user_height;
  87.         }
  88.         else {
  89.             bitmap_width = papersizes[i].width;
  90.             bitmap_height = papersizes[i].height;
  91.         }
  92.     }
  93.     bitmap_width  = (unsigned int)(bitmap_width  / 72.0 * xdpi);
  94.     bitmap_height = (unsigned int)(bitmap_height / 72.0 * ydpi);
  95. }
  96.  
  97. /* change the size of the gswin image if open */
  98. void
  99. gswin_resize()
  100. {
  101. BOOL display = FALSE;
  102. BOOL opened_dfile = FALSE;
  103.     gswin_size();
  104.     if (gswin_hinst == (HINSTANCE)NULL)
  105.         return;
  106.     if ( (dfile == (FILE *)NULL) && (doc != (struct document *)NULL) ) {
  107.         dfreopen();
  108.         opened_dfile = TRUE;
  109.     }
  110.     if (redisplay && page_ready && (doc != (struct document *)NULL))
  111.         display = TRUE;    /* redisplay page after resize */
  112.     gsview_endfile();
  113.     if (gswin_hinst != (HINSTANCE)NULL) {
  114.         fprintf(cfile,"mark /HWSize [%u %u]\r\n",bitmap_width,bitmap_height);
  115.         fprintf(cfile,"/HWResolution [%g %g]\r\n",xdpi,ydpi);
  116.         fprintf(cfile,"currentdevice putdeviceprops pop erasepage flushpage\r\n");
  117.         pipeflush();
  118.     }
  119.     if (display) {
  120.         if (gswin_hinst != (HINSTANCE)NULL)
  121.             gswin_open();    /* we need it open to redisplay */
  122.            fix_orientation(cfile);
  123.            dsc_header(cfile);
  124.         dsc_getpages(cfile,pagenum,pagenum);
  125.         pipeflush();
  126.     }
  127.  
  128.     if (opened_dfile)
  129.         dfclose();
  130. }
  131.  
  132. void
  133. gsview_orientation(int new_orientation)
  134. {
  135.     if (new_orientation == orientation)
  136.         return;
  137.     if (new_orientation == IDM_SWAPLANDSCAPE) {
  138.         swap_landscape = !swap_landscape;
  139.         if (swap_landscape) 
  140.             CheckMenuItem(hmenu, IDM_SWAPLANDSCAPE, MF_BYCOMMAND | MF_CHECKED);
  141.         else
  142.             CheckMenuItem(hmenu, IDM_SWAPLANDSCAPE, MF_BYCOMMAND | MF_UNCHECKED);
  143.         if ((orientation != IDM_LANDSCAPE) && (orientation != IDM_SEASCAPE))
  144.             return;
  145.     }
  146.     else {
  147.         CheckMenuItem(hmenu, orientation, MF_BYCOMMAND | MF_UNCHECKED);
  148.         orientation = new_orientation;
  149.         CheckMenuItem(hmenu, orientation, MF_BYCOMMAND | MF_CHECKED);
  150.     }
  151.     gswin_resize();
  152.     return;
  153. }
  154.  
  155. void
  156. gsview_media(int new_media)
  157. {
  158.     if ( (new_media == media) && (new_media != IDM_USERSIZE) )
  159.         return;
  160.     CheckMenuItem(hmenu, media, MF_BYCOMMAND | MF_UNCHECKED);
  161.     media = new_media;
  162.     CheckMenuItem(hmenu, media, MF_BYCOMMAND | MF_CHECKED);
  163.     gswin_resize();
  164.     return;
  165. }
  166.  
  167. /* run Ghostscript for previewing document */
  168. /* return TRUE if ok, FALSE if error */
  169. BOOL
  170. gswin_open()
  171. {
  172. char command[256];
  173.     /* return if already open */
  174.     if ((gswin_hinst != (HINSTANCE)NULL) && IsWindow(hwndimgchild))
  175.         return TRUE;
  176.  
  177.     pipeinit();        /* so we wait for first request */
  178.     gswin_size();
  179.     sprintf(command,"%s -r%gx%g -g%ux%u -sGSVIEW=%u -",
  180.         szGSwin, xdpi, ydpi, bitmap_width, bitmap_height,
  181.         (unsigned int)hwndimg);
  182.     if (strlen(command) > 126) {
  183.         info_wait(FALSE);
  184.         gserror(IDS_TOOLONG, command, MB_ICONSTOP, SOUND_ERROR);
  185.         gswin_hinst = (HINSTANCE)NULL;
  186.         return FALSE;
  187.     }
  188.     gswin_hinst = (HINSTANCE)WinExec(command, SW_SHOWMINNOACTIVE);
  189.  
  190.     if (gswin_hinst < HINSTANCE_ERROR) {
  191.         info_wait(FALSE);
  192.         gserror(IDS_CANNOTRUN, command, MB_ICONSTOP, SOUND_ERROR);
  193.         gswin_hinst = (HINSTANCE)NULL;
  194.         return FALSE;
  195.     }
  196.     if (hwndtext == (HWND)NULL) {
  197.         /* we are running an incompatible version of Ghostscript */
  198.         hwndtext = FindWindow("BCEasyWin","Ghostscript");
  199.         if (hwndtext) {
  200.             SendMessage(hwndtext, WM_CHAR, 'q', 1L);
  201.             SendMessage(hwndtext, WM_CHAR, 'u', 1L);
  202.             SendMessage(hwndtext, WM_CHAR, 'i', 1L);
  203.             SendMessage(hwndtext, WM_CHAR, 't', 1L);
  204.             SendMessage(hwndtext, WM_CHAR, '\r', 1L);
  205.         }
  206.         hwndtext = (HWND)NULL;
  207.         hwndimgchild = (HWND)NULL;
  208.         gswin_hinst = (HINSTANCE)NULL;
  209.         clear_timer();
  210.         info_wait(FALSE);
  211.         gserror(IDS_WRONGGS, NULL, MB_ICONSTOP, SOUND_ERROR);
  212.         return FALSE;
  213.     }
  214.     saved = FALSE;
  215.  
  216.     /* wait for gswin to initialise */
  217.     if (set_timer(CLOSE_TIMEOUT))
  218.         EnableWindow(hwndimg, FALSE);
  219.     while (!is_pipe_done()&&  !bTimeout)
  220.         do_message();    /* wait for pipe data request from gswin */
  221.     clear_timer();
  222.     EnableWindow(hwndimg, TRUE);
  223.  
  224.     cfile = pipeopen();    /* open pipe to gswin */
  225.     BringWindowToTop(hwndimg);
  226.     SetFocus(hwndimg);    /* kludge: without this desktop gets focus */
  227.     return TRUE;
  228. }
  229.  
  230. /* close Ghostscript */
  231. BOOL
  232. gswin_close()
  233. {
  234. BOOL force = FALSE;
  235.     if (gswin_hinst == (HINSTANCE)NULL)
  236.         return TRUE;
  237.  
  238.     if (doc == (struct document*)NULL) {
  239.         /* we don't know how many pages remain so we must force an exit */
  240.         if (!is_pipe_done())
  241.         force = TRUE;
  242.     }
  243.     else {
  244.         if (page_ready)
  245.         next_page();
  246.     }
  247.  
  248.     if (!force) {
  249.         /* try to close Ghostscript cleanly */
  250.         pipeclose();
  251.         if (set_timer(CLOSE_TIMEOUT))
  252.         EnableWindow(hwndimg, FALSE);
  253.         while (GetModuleUsage(gswin_hinst) &&  !bTimeout)
  254.         do_message();    /* wait for gswin to close */
  255.         clear_timer();
  256.         EnableWindow(hwndimg, TRUE);
  257.     }
  258.     do_message();
  259.  
  260.     /* if still there try killing it a using a brute force method */
  261.     if (IsWindow(hwndtext)) {
  262.         if (is_win31) {
  263.             SendMessage(hwndtext, WM_CLOSE, 0, 0L);
  264.             if (IsWindow(hwndtext))
  265.             SendMessage(hwndtext, WM_CLOSE, 0, 0L);
  266.         }
  267.         else {
  268.             /* Windows 3.0 hangs if we use SendMessage */
  269.             PostMessage(hwndtext, WM_CLOSE, 0, 0L);
  270.             do_message();
  271.         }
  272.     }
  273.  
  274.     do_message();
  275.     gswin_hinst = (HINSTANCE)NULL;
  276.     hwndimgchild = (HWND)NULL;
  277.     hwndtext = (HWND)NULL;
  278.     bitmap_scrollx = bitmap_scrolly = 0;
  279.     page_ready = FALSE;
  280.     saved = FALSE;
  281.     pipeclose();
  282.     return TRUE;
  283. }
  284.  
  285. /* send a NEXT_PAGE message to Ghostscript */
  286. void
  287. next_page()
  288. {
  289. int i;
  290.     if (hwndimgchild && IsWindow(hwndimgchild)) {
  291.         SendMessage(hwndimgchild, WM_GSVIEW, NEXT_PAGE, 0L);
  292.         page_ready = FALSE;
  293.     }
  294.     do_message();    /* wait for Ghostscript to process message */
  295.     for (i=0; i<32; i++) {
  296.        /* Wait a bit for pipe contents after showpage to be read */
  297.        do_message();
  298.        if (is_pipe_done())
  299.         break;
  300.     }
  301. }
  302.  
  303. /* handle messages while we are waiting */
  304. void
  305. do_message()
  306. {
  307.     MSG msg;
  308.     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
  309.     if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  310.             TranslateMessage(&msg);
  311.             DispatchMessage(&msg);
  312.         }
  313.     }
  314. }
  315.  
  316.  
  317. /* end of file - get ready for new file */
  318. void
  319. gsview_endfile()
  320. {
  321.     info_wait(TRUE);
  322.     if (gswin_hinst == (HINSTANCE)NULL)
  323.         return;
  324.     if (!quick ||
  325.              ((doc == (struct document *)NULL) && !is_pipe_done())) {
  326.         gswin_close();
  327.         return;
  328.     }
  329.  
  330.     if (page_ready)
  331.         next_page();
  332.  
  333.     if ((saved) && (doc != (struct document *)NULL) && (doc->pages)) {
  334.         /* send trailer if needed */
  335.         pscopy(dfile, cfile, doc->begintrailer, doc->endtrailer);
  336.     }
  337.     if (saved) {
  338.         /* restore interpreter state */
  339.         fputs("gsview_cleanup\r\n",cfile);
  340.         fputs("gsview_save restore\r\n",cfile);
  341.     }
  342.     else
  343.         fputs("clear cleardictstack\r\n",cfile);
  344.     pipeflush();
  345.     saved = FALSE;
  346. }
  347.  
  348. /* open a new document */
  349. void
  350. gsview_openfile(char *filename)
  351. {
  352. int i;
  353.     pagenum = 1;
  354.     if (dsc_scan(filename)) {
  355.         /* found DSC comments */
  356.         if (doc->orientation == PORTRAIT)
  357.         gsview_orientation(IDM_PORTRAIT);
  358.         if (doc->orientation == LANDSCAPE)
  359.         gsview_orientation(IDM_LANDSCAPE);
  360.         if (doc->default_page_media) {
  361.         char medianame[20];
  362.         for (i=IDM_LETTER; i<IDM_USERSIZE; i++) {
  363.             GetMenuString(hmenu, i, medianame, sizeof(medianame), MF_BYCOMMAND);
  364.             if (!stricmp(medianame, doc->default_page_media->name)) {
  365.                 gsview_media(i);
  366.                 break;
  367.             }
  368.         }
  369.         if (i == IDM_USERSIZE) {
  370.             gsview_media(IDM_USERSIZE);
  371.             user_width  = doc->default_page_media->width;
  372.             user_height = doc->default_page_media->height;
  373.         }
  374.         }
  375.     }
  376. }
  377.  
  378.  
  379. /* get filename then open new file for printing or extract */
  380. void 
  381. gsview_select()
  382. {
  383.     LoadString(phInstance, IDS_TOPICOPEN, szHelpTopic, sizeof(szHelpTopic));
  384.     if (GetOpenFileName(&ofn))
  385.         gsview_selectfile(szOFilename);
  386. }
  387.  
  388. /* open new file for printing or extract */
  389. void
  390. gsview_selectfile(char *filename)
  391. {
  392.     if (gswin_hinst != (HINSTANCE)NULL)
  393.         gsview_endfile();
  394.     gsview_openfile(filename);
  395.     info_wait(FALSE);
  396. }
  397.  
  398. /* get filename then open a new document and display it */
  399. void 
  400. gsview_display()
  401. {
  402.     LoadString(phInstance, IDS_TOPICOPEN, szHelpTopic, sizeof(szHelpTopic));
  403.     if (GetOpenFileName(&ofn))
  404.         gsview_displayfile(szOFilename);
  405. }
  406.  
  407. /* open a new document and display it */
  408. void
  409. gsview_displayfile(char *filename)
  410. {
  411. char *p;
  412.     gsview_endfile();
  413.  
  414.     info_wait(TRUE);
  415.  
  416.     gsview_openfile(filename);
  417.     if (epsf_clipped ||
  418.          ((doc != (struct document *)NULL) && doc->epsf && epsf_clip))
  419.         gswin_resize();
  420.  
  421.     if (!gswin_open()) {
  422.         MessageBox(hwndimg, "panic gsview_displayfile", szAppName, MB_OK);
  423.     }
  424.  
  425.     fix_orientation(cfile);
  426.     if (doc != (struct document *)NULL) {
  427.         /* found DSC comments */
  428.         dsc_header(cfile);
  429.         dsc_getpages(cfile,pagenum,pagenum);
  430.     }
  431.     else {
  432.         /* non conformant file - send unmodified */
  433.         fputs("(Displaying ",cfile);
  434.         for (p=filename; *p; p++) {
  435.         if (*p != '\\')
  436.             fputc(*p,cfile);
  437.         else
  438.             fputc('/',cfile);
  439.         }
  440.         fputs("\\n) print flush\r\n",cfile);
  441.         fputc('(',cfile);
  442.         for (p=filename; *p; p++) {
  443.         if (*p != '\\')
  444.             fputc(*p,cfile);
  445.         else
  446.             fputc('/',cfile);
  447.         }
  448.         fputs(") run flushpage\r\n",cfile);
  449.     }
  450.     
  451.     pipeflush();
  452. }
  453.  
  454.  
  455. void
  456. send_prolog(FILE *f, char *resource)
  457. {  
  458. HGLOBAL hglobal;
  459. LPSTR prolog;
  460.     hglobal = LoadResource(phInstance, FindResource(phInstance, resource, RT_RCDATA));
  461.     if ( (prolog = (LPSTR)LockResource(hglobal)) != (LPSTR)NULL) {
  462.         while (*prolog)
  463.             fputc(*prolog++, f);
  464.         FreeResource(hglobal);
  465.     }
  466. }
  467.  
  468.  
  469. /* add Ghostscript code to change orientation */
  470. void
  471. fix_orientation(FILE *f)
  472. {
  473. int real_orientation;
  474.     /* save interpreter state */
  475.     fputs("clear cleardictstack save /gsview_save exch def\r\n",f);
  476.     saved = TRUE;
  477.     /* provide epsf offset */
  478.     if (epsf_clipped)
  479.         fprintf(f,"/gsview_offset {%d %d translate} def\r\n",
  480.             -doc->boundingbox[LLX], -doc->boundingbox[LLY]);
  481.     else
  482.         fprintf(f,"/gsview_offset {} def\r\n");
  483.     real_orientation = orientation;
  484.     if (swap_landscape) {
  485.         if (orientation == IDM_LANDSCAPE)
  486.         real_orientation = IDM_SEASCAPE;
  487.         else if (orientation == IDM_SEASCAPE)
  488.         real_orientation = IDM_LANDSCAPE;
  489.     }
  490.     fprintf(f,"/gsview_landscape  %s def\r\n",
  491.         real_orientation == IDM_LANDSCAPE ? "true" : "false");
  492.     fprintf(f,"/gsview_upsidedown %s def\r\n",
  493.         real_orientation ==  IDM_UPSIDEDOWN ? "true" : "false");
  494.     fprintf(f,"/gsview_seascape   %s def\r\n",
  495.         real_orientation == IDM_SEASCAPE ? "true" : "false");
  496.     send_prolog(f, "gsview_orientation");
  497.     if (epsf_warn)
  498.         send_prolog(f, "gsview_epswarn");
  499. }
  500.  
  501. /* Create and open a scratch file with a given name prefix. */
  502. /* Write the actual file name at fname. */
  503. FILE *
  504. gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
  505. {    char *temp;
  506.     if ( (temp = getenv("TEMP")) == NULL )
  507.         *fname = 0;
  508.     else
  509.     {    strcpy(fname, temp);
  510.         /* Prevent X's in path from being converted by mktemp. */
  511.         for ( temp = fname; *temp; temp++ )
  512.             *temp = tolower(*temp);
  513.         if ( strlen(fname) && (fname[strlen(fname)-1] != '\\') )
  514.             strcat(fname, "\\");
  515.     }
  516.     strcat(fname, prefix);
  517.     strcat(fname, "XXXXXX");
  518.     mktemp(fname);
  519.     return fopen(fname, mode);
  520. }
  521.  
  522. /* reopen dfile */
  523. /* if dfile time/date or length has changed, kill gswin and rescan the file */
  524. BOOL
  525. dfreopen()
  526. {
  527. struct ftime thisftime;
  528. long thisflength;
  529.     if (doc == (struct document *)NULL)
  530.         return TRUE;
  531.     dfclose();
  532.     if (dfname[0] == '\0')
  533.         return TRUE;
  534.     if ( (dfile = fopen(efname[0] ? efname : dfname, "rb")) 
  535.             == (FILE *)NULL ) {
  536.         if (debug)
  537.             MessageBox(hwndimg, "file missing", "dfreopen", MB_OK);
  538.         dfname[0] = '\0';
  539.         return FALSE;
  540.     }
  541.     getftime(fileno(dfile), &thisftime);
  542.     thisflength = filelength(fileno(dfile));
  543.     if ( (thisflength != dflength) ||
  544.         memcmp(&thisftime, &dftime, sizeof(thisftime)) ) {
  545.         if (debug)
  546.             MessageBox(hwndimg, "file changed", "dfreopen", MB_OK);
  547.         /* file may have changed beyond recognition so we must kill gswin */
  548.         gswin_close();
  549.         if (dsc_scan(dfname))
  550.             if ( (dfile = fopen(efname[0] ? efname : dfname, "rb")) 
  551.                 == (FILE *)NULL ) {
  552.                 dfname[0] = '\0';
  553.                 return FALSE;
  554.             }
  555.     }
  556.     return TRUE;
  557. }
  558.  
  559. void
  560. dfclose()
  561. {
  562.     if (dfile != (FILE *)NULL)
  563.         fclose(dfile);
  564.     dfile = (FILE *)NULL;
  565. }
  566.  
  567. /* scan file for PostScript Document Structuring Conventions */
  568. /* return TRUE if valid DSC comments found */
  569. BOOL
  570. dsc_scan(char *filename)
  571. {
  572. unsigned char eps[4];
  573.     strcpy(dfname, filename);
  574.     dfclose();
  575.     if ((efname[0] != '\0') && !debug)
  576.         unlink(efname);
  577.     efname[0] = '\0';
  578.     if ( (dfile = fopen(dfname, "rb")) == (FILE *)NULL ) {
  579.         dfname[0] = '\0';
  580.         return FALSE;
  581.     }
  582.     getftime(fileno(dfile), &dftime);
  583.     dflength = filelength(fileno(dfile));
  584.     if (page_list.select)
  585.         free(page_list.select);
  586.     page_list.select = NULL;
  587.     if (doc)
  588.         psfree(doc);
  589.     is_ctrld = FALSE;
  590.     fread(eps, 1, 4, dfile);
  591.     if ((eps[0]==0xc5) && (eps[1]==0xd0) && (eps[2]==0xd3) && (eps[3]==0xc6))
  592.         extract_eps();
  593.     else
  594.         preview = 0;
  595.     doc = psscan(dfile);
  596.     if (doc == (struct document *)NULL) {
  597.         dfclose();
  598.         return FALSE;
  599.     }
  600.     if (eps[0] == '\004')
  601.         is_ctrld = TRUE;
  602.     if (!preview && doc->beginpreview)
  603.         preview = IDS_EPSI;
  604.     page_list.select = (BOOL *)malloc( doc->numpages * sizeof(BOOL) );
  605.     return TRUE;
  606. }
  607.  
  608.  
  609.  
  610. /* Copy specified pages from dfile to file f */
  611. void
  612. dsc_getpages(FILE *f, int first, int last)
  613. {
  614. int i, page;
  615.     for (i=first-1; i<last; i++) {
  616.         page = map_page(i);
  617.         if (doc->pages) {
  618.             fprintf(f,"(Page: %s %d\\n) print flush\r\n", doc->pages[page].label ? doc->pages[page].label : " ", page+1);
  619.         pscopy(dfile, f, doc->pages[page].begin, doc->pages[page].end);
  620.         }
  621.         else {
  622.             fprintf(f,"(Page: %d\\n) print flush\r\n",page); 
  623.         pscopy(dfile, f, doc->endsetup, doc->endtrailer);
  624.         }
  625.     }
  626. }
  627.  
  628.  
  629. /* Copy dsc header to file f */
  630. void
  631. dsc_header(FILE *f)
  632. {
  633. char *p;
  634.     fputs("(Displaying ",f);
  635.     for (p=dfname; *p; p++) {
  636.         if (*p != '\\')
  637.         fputc(*p,f);
  638.         else
  639.         fputc('/',f);
  640.     }
  641.     fputs("\\n) print flush\r\n",f);
  642.     pscopy(dfile, f, doc->beginheader, doc->endheader);
  643.     pscopy(dfile, f, doc->begindefaults, doc->enddefaults);
  644.     pscopy(dfile, f, doc->beginprolog, doc->endprolog);
  645.     pscopy(dfile, f, doc->beginsetup, doc->endsetup);
  646. }
  647.  
  648.  
  649. /* Send commands to gswin to display page */
  650. void
  651. dsc_dopage(void)
  652. {
  653.     info_wait(TRUE);
  654.     if (!saved) {
  655.            fix_orientation(cfile);
  656.            dsc_header(cfile);
  657.     }
  658.     dsc_getpages(cfile,pagenum,pagenum);
  659.     pipeflush();
  660. }
  661.  
  662. /* go forward skip pages */
  663. void
  664. dsc_next(int skip)
  665. {
  666.     if (pagenum == doc->numpages || doc->numpages == 0) {
  667.         play_sound(SOUND_NOPAGE);
  668.         info_wait(FALSE);
  669.         return;
  670.     }
  671.     pagenum += skip;
  672.     if (pagenum > doc->numpages)
  673.          pagenum = doc->numpages;
  674.     info_wait(TRUE);
  675.     if (page_ready)
  676.         next_page();
  677.     if (gswin_open())
  678.         dsc_dopage();
  679. }
  680.  
  681. /* go back skip pages */
  682. void
  683. dsc_prev(int skip)
  684. {
  685.     if (pagenum == 1 || doc->numpages == 0) {
  686.         play_sound(SOUND_NOPAGE);
  687.         return;
  688.     }
  689.     pagenum -= skip;
  690.     if (pagenum < 1)
  691.         pagenum = 1;
  692.     info_wait(TRUE);
  693.     if (page_ready)
  694.         next_page();
  695.     if (gswin_open())
  696.         dsc_dopage();
  697. }
  698.  
  699. /* reverse zero based page number if needed */
  700. int
  701. map_page(int page)
  702. {
  703.         if (doc->pageorder == DESCEND) 
  704.         return (doc->numpages - 1) - page;
  705.     return page;
  706. }
  707.